
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.IO;
using System.Collections;
using System.Diagnostics;

using Swaf.Xml;
using Swaf;
using Swaf.Container;

namespace Swaf.Logging
{
	/// <summary>
	/// Summary description for FileLogLogObserver.
	/// </summary>
	public class FileLogObserver : BaseLogObserver 
	{
		StreamWriter m_log;
		IApplication m_app;
		string m_logFileName;
		long m_maxFileSizeInBytes = -1;
		int m_maxFileCount=1;
		int m_curFileNum = 0;
		string m_curFileName="";

		public FileLogObserver() : base()
		{
			init();
		}
		public FileLogObserver(string fileName) : base()
		{
			m_logFileName=fileName;
			init();
		}
		public FileLogObserver(bool logCaller) : base(logCaller)
		{
			init();
		}
		public FileLogObserver(string fileName,bool logCaller) : base(logCaller)
		{
			m_logFileName=fileName;
			init();
		}

		public FileLogObserver(bool logCaller, int maxFiles,long maxSize) : base(logCaller)
		{
			m_maxFileCount = maxFiles;
			m_maxFileSizeInBytes = maxSize;
			init();
		}
		public FileLogObserver(string fileName, bool logCaller, int maxFiles,long maxSize) : base(logCaller)
		{
			m_logFileName=fileName;
			m_maxFileCount = maxFiles;
			m_maxFileSizeInBytes = maxSize;
			init();
		}
		public FileLogObserver(int maxFiles, long maxSize) : base()
		{	
			m_maxFileCount = maxFiles;
			m_maxFileSizeInBytes = maxSize;
			init();
		}
		public FileLogObserver(string fileName,int maxFiles, long maxSize) : base()
		{	
			m_logFileName=fileName;
			m_maxFileCount = maxFiles;
			m_maxFileSizeInBytes = maxSize;
			init();
		}

		private void setCurrentFileNum()
		{
			string actualFileName="";
			int calcedFile=0;
			int lastEmptyFile=-1;
			lock(this)
			{
				FileInfo fInfo = null;
				if ( (m_maxFileSizeInBytes == -1) || (! File.Exists(m_logFileName)))
					currentFileNumber = 0;
				else
				{
					for(int fileIdx=m_maxFileCount-1; fileIdx >= 0; --fileIdx)
					{
						actualFileName = buildLogName(fileIdx);
						if (File.Exists(actualFileName))
						{
							fInfo = new FileInfo(actualFileName);
							if (fInfo.Length  < m_maxFileSizeInBytes)
							{
								calcedFile=fileIdx;	
								break;
							}
							else
							{
								if (lastEmptyFile != -1)
								{
									calcedFile=lastEmptyFile;
									break;
								}
							}
						}
						else
						{
							lastEmptyFile = fileIdx;
						}
					}
					currentFileNumber=calcedFile;
				}
			}

		}
		private int currentFileNumber
		{
			set 
			{
				m_curFileNum=value;
				m_curFileName="";
			}
			get
			{
				return m_curFileNum;
			}
		}
		private string buildLogName(int fileIndex)
		{
			string actualFileName="";
			string extName = Path.GetExtension(m_logFileName);
			string fileName = Path.GetFileNameWithoutExtension(m_logFileName);
			if (fileIndex > 0)
				actualFileName=m_logFileName.Substring(0,m_logFileName.Length - extName.Length) + "_" + fileIndex.ToString() + extName;
			else
				actualFileName = m_logFileName;
			return actualFileName;

		}
		private string buildLogName()
		{
			if (m_curFileName.Length == 0)
			{
				return buildLogName(m_curFileNum);
			}
			else
				return m_curFileName;
		}
		public void init()
		{
			m_app=Application.currentApp;
			if (m_logFileName == null || m_logFileName=="")
				m_logFileName=@"$LogFile$";
			m_logFileName = m_app.resMgr.resolve(m_logFileName);
            if (m_logFileName.ToLower().StartsWith("file://"))
                m_logFileName = m_logFileName.Substring(7); //Remove the beginning file://
			setCurrentFileNum();
			((Application) m_app).OnAppShutdown += new AppShutdownRequest(shutDown);

			writeToFile(String.Format("************* Begin Logging Session ***************"),true);
		}
		public void shutDown(IApplication app)
		{
			writeToFile(String.Format("************* End Logging Session ***************"),true);
		}
		public void writeEntry(IDictionary info)
		{
			//if(m_log != null)
			//{
				string message="";
				if (info["message"].GetType() == typeof(INameAddressSupport))
					message = ((INameAddressSupport) info["message"]).Xml;
				else
					message = info["message"].ToString();
				writeToFile(message, (bool) info["newLine"]);
			//}

		}
		private void writeToFile(string message, bool newLine)
		{
			try
			{
				string actualFileName="";
				actualFileName = buildLogName();
				
				FileInfo fInfo = null;
				bool rollFile = false;
				if (File.Exists(actualFileName))
				{
					fInfo = new FileInfo(actualFileName);
					rollFile = ((m_maxFileSizeInBytes != -1) && (fInfo.Length  >= m_maxFileSizeInBytes));
				}
				bool append=(! rollFile);
				if (rollFile)
				{
					if (++m_curFileNum == m_maxFileCount)
						m_curFileNum = 0;
				}

				actualFileName = buildLogName();

				//If we don't append, we need to force a newline.
				if (! append)
					newLine = true;
				m_log = new StreamWriter(actualFileName,append);
				if (newLine)
					m_log.WriteLine(currentDateTime() + "    " + message);
				else
					m_log.Write(message);
				m_log.Close();
			}
			catch(Exception e)
			{
				EventLog.WriteEntry("Swaf.Logging.FileLogObserver",String.Format("Error opening log file '{0}'.  Error was: {1}",m_logFileName,e.ToString()),EventLogEntryType.Error);				
			}
		}
		private string currentDateTime()
		{
			return DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss:fffffff tt");
		}
	}
}
